using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Ace;
using Ace.Web;
using System.Windows;
using System.IO;
using System.Diagnostics;
using System.Net;
using System.Reflection;
using System.Threading;
using MalwarePatch.Languages;
using MalwarePatch.Windows.Main;

namespace MalwarePatch.Models
{
    sealed class Updater
    {
        /// <summary>
        /// 更新源的ID
        /// </summary>
        private const string UpdateId = "0B4uebmDoSFx-c0kzcG5yVlZVMlE";
        public string Proxy { get; set; }
        private UpdateLanguage Languages { get; } = new UpdateLanguage();
        public DownloadProgressChangedEventHandler ProgressChanged { get; set; }

        public const string
            UpdateFileName = "__mwp.exe",
            UpdateParameter = "--update",
            RestartParameter = "--restart",
            RemoveOldFileParameter = "--remove";
        public Task<FileInfo> DownloadUpdate()
        {
            if (Process.GetCurrentProcess().MainModule.FileName.GetFileName() == UpdateFileName)
            {
                var message = Languages[UpdateLanguage.Keys.UpdateFromPreupdateFile];
                throw new InvalidOperationException(message);
            }
            if (File.Exists(UpdateFileName))
            {
                File.Delete(UpdateFileName);
            }
            var downloadLink = "https://cdn.jsdelivr.net/gh/the1812/Malware-Patch@master/mwp.exe";
            // var downloadLink = "https://github.com/the1812/malware-patch/raw/master/mwp.exe";
            // var downloadLink = GoogleDrive.GetDirectLinkFromId(UpdateId);
            var info = new DownloadInfo(downloadLink)
            {
                Proxy = Proxy,
                ProgressChanged = ProgressChanged,
            };
            return info.DownloadFileAsync(UpdateFileName);
        }
        public string RestartParameters { get; set; } = "";
        public void SetUpdatePlan()
        {
            Application.Current.Exit += (s, e) =>
            {
                if (File.Exists(UpdateFileName))
                {
                    var startInfo = new ProcessStartInfo(UpdateFileName)
                    {
                        Arguments = $"{UpdateParameter}={(Process.GetCurrentProcess().MainModule.FileName.GetFileName()).Quotes()} {RestartParameters}",
                        WorkingDirectory = Environment.CurrentDirectory,
                        UseShellExecute = false,
                    };
                    Process.Start(startInfo);
                }
            };
        }
        /// <summary>
        /// 安装更新(如果有)并启动应用
        /// </summary>
        /// <param name="app">应用</param>
        /// <param name="args">命令行参数</param>
        public static void InstallUpdateAndRun(App app, string[] args)
        {
            const int maxWaitTimes = 60;
            var waitTimes = 0;
            void removeUpdateFile()
            {
                var selfFileName = Process.GetCurrentProcess().MainModule.FileName.GetFileName();
                var fileNameToRemove = UpdateFileName;
                if (selfFileName != fileNameToRemove
                    && File.Exists(fileNameToRemove))
                {
                    //Ensure the old app has exited
                    while (Utils.IsRunning(fileNameToRemove))
                    {
                        Thread.Sleep(500);
                        waitTimes++;
                        if (waitTimes > maxWaitTimes)
                        {
                            app.Shutdown();
                        }
                    }
                    Thread.Sleep(500);
                    File.Delete(fileNameToRemove);
                }
            }
            void copyUpdateFile(Dictionary<string, string> dictionary)
            {
                var targetFileName = dictionary[UpdateParameter].NoQuotes();
                var selfFileName = Process.GetCurrentProcess().MainModule.FileName.GetFileName();
#if DEBUG
                //MessageBox.Show(targetFileName, selfFileName);
#endif
                if (!selfFileName.EqualsIgnoreCase(targetFileName))
                {
                    //Ensure the old app has exited
                    while (Utils.IsRunning(targetFileName))
                    {
                        Thread.Sleep(500);
                        waitTimes++;
                        if (waitTimes > maxWaitTimes)
                        {
                            app.Shutdown();
                        }
                    }
                    //Thread.Sleep(500);
                    File.Copy(selfFileName, targetFileName, true);
                    Process.Start(new ProcessStartInfo
                    {
                        FileName = targetFileName,
                        WorkingDirectory = Environment.CurrentDirectory,
                        Arguments = RemoveOldFileParameter,
                    });
                    //Check if restart is required
                    if (dictionary.ContainsKey(RestartParameter))
                    {
                        var arguments = new Dictionary<string, string>(dictionary);
                        arguments.Remove(RestartParameter);
                        arguments.Remove(UpdateParameter);
                        Process.Start(new ProcessStartInfo
                        {
                            Arguments = string.Join(" ", arguments.Select(kv =>
                            {
                                if (kv.Value is null)
                                {
                                    return kv.Key;
                                }
                                else
                                {
                                    return $"{kv.Key}={kv.Value}";
                                }
                            })),
                            FileName = targetFileName,
                            WorkingDirectory = Environment.CurrentDirectory,
                        });
                    }
                }
            }
            if ((args?.Length ?? -1) > 0)
            {
                var oldVersionParameter = $"{UpdateParameter}:";
                var flattenedArgs = string.Join(" ", args);
                Dictionary<string, string> dictionary = null;
                if (!flattenedArgs.Contains(oldVersionParameter))
                {
                    dictionary = flattenedArgs.SplitToDictionary(" ", "=", true);
                }
                else
                {
                    dictionary = flattenedArgs.SplitToDictionary(" ", ":", true);
                }
#if DEBUG
                File.AppendAllText("args.txt", Environment.NewLine + flattenedArgs);
#endif

                if (dictionary.ContainsKey(UpdateParameter))
                {
                    copyUpdateFile(dictionary);
                }
                else if (dictionary.ContainsKey(RemoveOldFileParameter))
                {
                    removeUpdateFile();
                }
            }
            else
            {
                new MainWindow().ShowDialog();
            }
            app.Shutdown();
        }
    }
}
